package com.storydo.file.share.rest;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import com.storydo.file.share.base.controller.BaseController;
import com.storydo.file.share.config.FileConfiguration;
import com.storydo.file.share.project.file.entity.Sfile;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/file")
public class FileController extends BaseController {

	@Autowired
	FileConfiguration fileConfig;
	
	@RequestMapping("/home")
	public Object home(String path, Map<String, Object> param) {
		Path workPath = fileConfig.getWorkPath();
		Path homePath = workPath;
		if (!isNullOrEmpty(path)) {
			Path relate = Paths.get(path);
			if (!relate.isAbsolute() && !path.contains("..")) {				
				homePath = workPath.resolve(relate);
			}
		}
		List<Sfile> list = new ArrayList<Sfile>();
		try {
			list = Files.list(homePath).map(p -> new Sfile(p, workPath)).sorted((a, b) -> a.compareTo(b))
					.collect(Collectors.toList());
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		param.put("path", workPath.relativize(homePath).normalize().toString().replace("\\", "/"));
		param.put("parent", workPath.relativize(homePath.getParent()).toString().replace("\\", "/"));
		param.put("list", list);
		param.put("upload", fileConfig.isUpload());
		return "file/index";
	}
	private AntPathMatcher antPathMatcher = new AntPathMatcher();
	
	@ResponseBody
	@RequestMapping(value = "/download/**")
	public void download() throws IOException {
		String uri = (String)request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
		String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
		String file = antPathMatcher.extractPathWithinPattern(pattern, uri);
		if (file.contains("..")) {
			response.sendRedirect("error");
			return;
		}
		Path path = fileConfig.getWorkPath().resolve(file);
		if (!Files.exists(path) || Files.isDirectory(path)) {
			response.sendRedirect("error");
			return;
		}
		response.setContentType("application/octet-stream");
		long fileSize = Files.size(path);
		response.setContentLengthLong(fileSize);
		try(OutputStream os = response.getOutputStream();
			BufferedInputStream bis = 
					new BufferedInputStream(new FileInputStream(path.toFile()))) {
			int progress = 0; long downSize = 0; boolean print = true; int step = 0;
			byte[] tmp = new byte[1024*512];
			int len = 0; 
			while((len = bis.read(tmp, 0, tmp.length)) > 0) {				
				os.write(tmp, 0, len);
				downSize += len;
				progress = Double.valueOf(downSize * 100.0 / fileSize).intValue();
				if (progress >= step + 5) {
					step = progress;
					print = true;
				}
				if (print) {
					StringBuilder graph = new StringBuilder();
					for (int i = 0; i < progress / 5; i++) {
						graph.append("-");
					}
					log.info("下载进度: {} / {}%", graph.toString(), progress);
					print = false;
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}
	
	@ResponseBody
	@RequestMapping(value = "/upload", produces = "application/json;charset=UTF-8")
	public Object upload(@RequestParam("file") MultipartFile[] fileList) {
		if (!fileConfig.isUpload()) {
			return error("请开启上传功能后使用");
		}
		try {
			Path uploadDir = fileConfig.getWorkPath().resolve("upload");
			if (!Files.exists(uploadDir)) {
				Files.createDirectories(uploadDir);
			}
			int i = 0;
			for (MultipartFile file : fileList) {
				log.info("{}/{} => name {}, size {}", ++i, fileList.length, file.getOriginalFilename(), file.getSize());	
				try (InputStream is = file.getInputStream()){
					Files.copy(is, uploadDir.resolve(file.getOriginalFilename()));
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				}
			}		
			return success();
		} catch (IOException e) {
			log.error(e.getMessage(), e);
			return error("server error");
		}
	}
	
}
